/**
 *    Copyright 2009-2015 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package com.yinsin.jpabatis.executor.loader;

import java.sql.SQLException;
import java.util.List;

import com.yinsin.jpabatis.cache.CacheKey;
import com.yinsin.jpabatis.config.Configuration;
import com.yinsin.jpabatis.executor.Executor;
import com.yinsin.jpabatis.executor.ResultExtractor;
import com.yinsin.jpabatis.mapper.BoundSql;
import com.yinsin.jpabatis.mapper.MappedStatement;
import com.yinsin.jpabatis.reflection.factory.ObjectFactory;
import com.yinsin.jpabatis.session.ExecutorType;

/**
 * @author Clinton Begin
 */
public class ResultLoader {

	protected final Configuration configuration;
	protected final Executor executor;
	protected final MappedStatement mappedStatement;
	protected final Object parameterObject;
	protected final Class<?> targetType;
	protected final ObjectFactory objectFactory;
	protected final CacheKey cacheKey;
	protected final BoundSql boundSql;
	protected final ResultExtractor resultExtractor;
	protected final long creatorThreadId;

	protected boolean loaded;
	protected Object resultObject;

	public ResultLoader(Configuration config, Executor executor, MappedStatement mappedStatement, Object parameterObject, Class<?> targetType, CacheKey cacheKey, BoundSql boundSql) {
		this.configuration = config;
		this.executor = executor;
		this.mappedStatement = mappedStatement;
		this.parameterObject = parameterObject;
		this.targetType = targetType;
		this.objectFactory = configuration.getObjectFactory();
		this.cacheKey = cacheKey;
		this.boundSql = boundSql;
		this.resultExtractor = new ResultExtractor(configuration, objectFactory);
		this.creatorThreadId = Thread.currentThread().getId();
	}

	public Object loadResult() throws SQLException {
		List<Object> list = selectList();
		resultObject = resultExtractor.extractObjectFromList(list, targetType);
		return resultObject;
	}

	private <E> List<E> selectList() throws SQLException {
		Executor localExecutor = executor;
		if (Thread.currentThread().getId() != this.creatorThreadId || localExecutor.isClose()) {
			localExecutor = newExecutor();
		}
		return localExecutor.<E> queryList(mappedStatement, parameterObject, Executor.NO_RESULT_HANDLER, cacheKey, boundSql);
	}

	private Executor newExecutor() {
		return configuration.newExecutor(ExecutorType.SIMPLE);
	}

	public boolean wasNull() {
		return resultObject == null;
	}

}
